
`define OP_ORA 3'd00
`define OP_AND 3'd01
`define OP_EOR 3'd02
`define OP_ADC 3'd03
// 5,6 分别是 sta,lda
`define OP_CMP 3'd06
`define OP_SBC 3'd07

module ALU (
    op1,
    op2,
    dest_out,
    P,
    opc,
    flg_out
);
`define OP_IS(hex) (opc==hex)
    input wire[7:0] op1,op2;
    input wire[7:0] P;
    output wire[7:0] dest_out;
    input wire[2:0]  opc;
    output wire[3:0] flg_out;

    wire[8:0] dest;

    wire[7:0]op2a = (`OP_IS(`OP_CMP)|`OP_IS(`OP_SBC)|`OP_IS(`OP_SBC)) ?~op2:op2;
    assign dest =
    `OP_IS(`OP_ADC)?({1'b0,op1}+{1'b0,op2a}+{8'd0,P[0]}):
    `OP_IS(`OP_SBC)?({1'b0,op1}+{1'b0,op2a}+{8'd0,P[0]}):       //如果使用减法,则会增加一些资源
    `OP_IS(`OP_ORA)?({1'b0,op1}|{1'b0,op2 }):
    `OP_IS(`OP_AND)?({1'b0,op1}&{1'b0,op2 }):
    `OP_IS(`OP_EOR)?({1'b0,op1}^{1'b0,op2 }):
    `OP_IS(`OP_CMP)?({1'b0,op1}+{1'b0,op2a}+9'd1):      //cmp
    9'd0;
    wire fZ;
    wire fN;
    wire fC;
    wire fV;
    assign fZ = dest[7:0]==0;
    assign fN = dest[7];
    //assign fC = (`OP_IS(`OP_SBC)|`OP_IS(`OP_CMP))?~dest[8]:dest[8];     //SBC可以取反变成ADC,但C位需要取反
    assign fC = ~(`OP_IS(`OP_ADC)|`OP_IS(`OP_SBC)|`OP_IS(`OP_CMP))?P[0]:        //除了ADC,SBC,CMP,其他的都不变
        (dest[8] /* ^(`OP_IS(`OP_SBC)|`OP_IS(`OP_CMP))*/);
    assign fV =
        ~(`OP_IS(`OP_ADC)|`OP_IS(`OP_SBC))?P[6]:        //除了ADC与SBC,其他都不变
        (((op1[7]&op2a[7])&~dest[7])          //情况1,如果op1与op2皆为负数,结果为正数.则溢出
        |((~op1[7]&~op2a[7])&dest[7]))        //情况2,如果op1与op2皆为正数,结果为负数,则溢出
    ;
    assign flg_out = {fN,fV,fZ,fC};
    assign dest_out = dest[7:0];
endmodule

module cpu(
    addr,
    dat,
    clk_in,
    rst_n,
    irq,
    nmi,
    rw
);
    input wire clk_in;
    inout wire[7:0] dat;
    input wire rst_n;
    output wire[15:0] addr;
    output wire rw;     reg rw_reg = 'b1; assign rw = rw_reg;
    input wire irq;
    input wire nmi;




    /////////////////////////////////////////////////////////
    reg [16:0] PC = 'd0;
    reg [15:0] cpu_addr = 'd0;
    reg [7:0]  cpu_out_dat = 'd0;
    reg [15:0] tmp_addr = 'h1234;
    reg [7:0] A = 'd12;  /*synthesis keep=1 */
    reg [7:0] X = 'hf0;
    reg [7:0] Y = 'he0;
    reg [7:0] P = 'h00;
    reg [7:0] S = 'h00;
    wire wIFLG = P[2];
    wire wCFLG = P[0];
    wire wZFLG = P[1];
    wire wDFLG = P[3];
    wire wBFLG = P[4];
    wire wUFLG = P[5];
    wire wVFLG = P[6];
    wire wNFLG = P[7];


    wire[7:0] insn_dat = (do_nmi|do_rst|do_irq)?8'h00:dat;

    /////////////////////////////////////////////////////////
    //一些宏
`define CPU_WDATA(addr,dat) \
    cpu_addr <= addr; cpu_out_dat <= dat; rw_reg <= 'b0;

`define CPU_SET_ADDR(addr) \
    if(~PC[16])begin PC <= {1'b1,addr}; end

`define CPU_SET_PC \
    cpu_addr <= PC[15:0];

`define CPU_PUSH(dat) \
    cpu_out_dat <=dat; rw_reg  <= 'b0;

`define CPU_SET_READ(addr) \
    `CPU_SET_ADDR(addr) rw_reg <= 'b1;

`define CPU_ADDR_INC \
    cpu_addr <= cpu_addr + 16'd1;
`define CPU_ADDR_DEC \
    cpu_addr <= cpu_addr - 16'd1;

`define CPU_POP(var)
`define CPU_POPP
`define CPU_JMP_ABS(addr) \
    cpu_addr <= addr; dor_jmp <= 'd1;

`define FLG_UPDATE_NZ(value) `ZFLG <= (value)=='h00; `NFLG <= value[7];
`define IFLG    P[2]
`define CFLG    P[0]
`define ZFLG    P[1]
`define DFLG    P[3]
`define BFLG    P[4]
`define UFLG    P[5]
`define VFLG    P[6]
`define NFLG    P[7]
`define JMP_BPL     (~`NFLG & (dat[7:5]=='h0))
`define JMP_BMI     ( `NFLG & (dat[7:5]=='h1))
`define JMP_BVC     (~`VFLG & (dat[7:5]=='h2))
`define JMP_BVS     ( `VFLG & (dat[7:5]=='h3))
`define JMP_BCC     (~`CFLG & (dat[7:5]=='h4))
`define JMP_BCS     ( `CFLG & (dat[7:5]=='h5))
`define JMP_BNE     (~`ZFLG & (dat[7:5]=='h6))
`define JMP_BEQ     ( `ZFLG & (dat[7:5]=='h7))


    /////////////////////////////////////////////////////////
    //处理线的关系
    assign dat = rw?8'hzz:cpu_out_dat;
    assign addr = cpu_addr;


    /////////////////////////////////////
    //定义一些状态机
    reg dor_brk = 'd0;
    reg dor_jsr = 'd0; reg dor_jsr2 = 'd0; reg dor_jsr3 = 'd0;
    reg dor_rti = 'd0;
    reg dor_rts = 'd0;
    reg dor_php = 'd0; reg dor_push_end = 'd0;
    reg dor_plp = 'd0;
    reg dor_pha = 'd0;
    reg dor_pla = 'd0;

    reg dor_dey = 'd0;
    reg dor_tay = 'd0;
    reg dor_iny = 'd0;
    reg dor_inx = 'd0;
    reg dor_txa = 'd0;
    reg dor_tax = 'd0;
    reg dor_dex = 'd0;
    reg dor_nop = 'd0; reg dor_nop1 = 'd0;
    reg dor_bpl = 'd0;
    reg dor_bmi = 'd0;
    reg dor_bvc = 'd0;
    reg dor_bvs = 'd0;
    reg dor_bcc = 'd0;
    reg dor_bcs = 'd0;
    reg dor_bne = 'd0;
    reg dor_beq = 'd0;
    reg dor_clc = 'd0;
    reg dor_sec = 'd0;
    reg dor_cli = 'd0;
    reg dor_sei = 'd0;
    reg dor_tya = 'd0;
    reg dor_clv = 'd0;
    reg dor_cld = 'd0;
    reg dor_sed = 'd0;
    reg dor_txs = 'd0;
    reg dor_tsx = 'd0;

    //种类状态
    reg dor_zp =  'd0;
    reg dor_zpx = 'd0;
    reg dor_abs = 'd0; reg dor_abs2 = 'd0;
    reg dor_abx = 'd0;
    reg dor_aby = 'd0;
    reg dor_abs_over = 'd0;
    reg dor_abs_over_sta = 'd0;
    reg dor_ind_x = 'd0;
    reg dor_ind_y = 'd0;

    reg dor_jmp =  'd0;
    reg dor_jmp2 = 'd0;
    reg dor_jmp3 = 'd0;
    reg dor_jmp_ind =  'd0;
    reg dor_rti2 = 'd0;

    reg dor_cpx = 'd0;
    reg dor_cpy = 'd0;

    //一些其他状态
    reg dor_pushP = 'd0;
    reg dor_pushPCL = 'd0;
    reg dor_m2a;
    reg dor_m2p;
    reg dor_restorePC = 'd0;
    reg dor_addr_sp = 'd0;
    reg do_fetch_opcode = 'd0;
    reg dor_jmp_td = 'd0;
    reg [7:0] insn_reg = 'd0;  /*synthesis keep=1 */
    wire dor_mem_access = dor_zp|dor_zpx|dor_abs|dor_abs2|dor_abs_over;
    reg dor_mem_access_firset = 'd0;
    reg dor_alu = 'd0;
    reg dor_sta = 'd0;
    reg dor_lda = 'd0;
    reg dor_ldx = 'd0;
    reg dor_ldy = 'd0;
    reg dor_stx = 'd0;
    reg dor_sty = 'd0;
    reg dor_jmprel = 'd0;
    reg dor_jmprel_over = 'd0;
    reg dor_writeback = 'd0;

    reg dor_inc = 'd0;
    reg dor_dec = 'd0;

    reg dor_asl = 'd0;
    reg dor_lsr = 'd0;
    reg dor_rol = 'd0;
    reg dor_ror = 'd0;
    reg dor_shift_A = 'd0;

    reg dor_bit = 'd0;

    wire[63:0] cpu_dor_status = {
    dor_jsr,
    dor_jmp,
    dor_jmp_ind,
    dor_brk,    //45
    dor_rti,
    dor_rts,
    dor_php,
    dor_plp,
    dor_pha,
    dor_pla,
    dor_dey,
    dor_tay,
    dor_iny,
    dor_inx,
    dor_txa,
    dor_tax,
    dor_dex,    //32
    dor_nop,
    dor_bpl,
    dor_bmi,
    dor_bvc,
    dor_bvs,
    dor_bcc,
    dor_bcs,
    dor_bne,
    dor_beq,
    dor_clc,
    dor_cli,
    dor_clv,
    dor_cld,
    dor_sec,
    dor_sei,
    dor_sed,
    dor_tya,
    dor_txs,
    dor_tsx,
    dor_sta,
    dor_lda,
    dor_cpx,
    dor_cpy,
    dor_alu,
    dor_zp,
    dor_zpx,
    dor_abs,
    dor_abx,
    dor_aby,
    dor_ind_x,
    dor_ind_y,
    dor_restorePC
    } ;

    wire[7:0] result;
    wire[7:0] op1 = dor_cpx?X:dor_cpy?Y:A;
    wire[7:0] op2 = dat;
    wire[3:0] flg_out;

    reg test_err = 'd0;
    reg test_nerr = 'd0;

    //wire test_addr = cpu_addr=='h8E16;
    //wire test_addr = cpu_addr=='h06&&~rw;
    wire test_addr = cpu_addr=='h354;

    // ALU alu(
    //     .op1(op1),
    //     .op2(op2),
    //     .dest_out(result),
    //     .P(P),
    //     .opc(opcode),
    //     .flg_out(flg_out)
    // );

    reg do_dma = 'd0;
    reg dma_init_flg = 'd0;
    reg end_dma =  'd0;
    reg[1:0] dma_read = 'd0;
    reg [15:0] dma_copy_addr = 'd0;
    wire start_dma = cpu_addr=='h4014&&~rw;
    always @(posedge start_dma or posedge end_dma) begin
        $display("start dma!%02X",dat);
        if(start_dma)begin
            do_dma <= 'b1;
            //开始复制
            dma_copy_addr[15:8] <= dat;
        end
        else if(end_dma)begin
            do_dma <= 'b0;
        end
    end

    task task_dma_copy; begin
        //处理dma的任务
        // if(do_dma)begin
        //     dma_init_flg <= 'b0;
        // end
        if(dma_read[1]==1'b0)begin
            //进行初始化
            //PC <= cpu_addr;       //不需要这条,已经备份了
            dma_read[1] <= 1'b1;
            dma_read[0] <= 'b1;
            cpu_addr <= dma_copy_addr;
            rw_reg <=  'b1;
            end_dma <= 'b0;     //dma结束标志
        end
        else begin
            dma_read[0] <= ~dma_read[0];
            //开始复制
            if(dma_read[0])begin
                //当前状态是读取.然后写出数据
                cpu_out_dat <= dat;
                cpu_addr <= 'h2004;
                rw_reg <= 'b0;
                //设置下一个位移
                dma_copy_addr[7:0] <= dma_copy_addr[7:0] + 8'd1;
            end
            else begin
                //设置读取
                rw_reg <= 'b1;
                cpu_addr <= dma_copy_addr;
                if(dma_copy_addr[7:0]=='h00)begin
                    dma_read <= 2'b00;
                    end_dma <= 1'b1;        //设置dma结束标志
                    cpu_addr <= PC;

                end
            end
        end

    end endtask

    ALU alu(
        (op1),
        (op2),
        (result),
        (P),
        (opcode),
        (flg_out)
    );

    task task_mem_access; begin
        if(dor_mem_access_firset)begin
            /*如果存在abs.则需要在abs2更新*/
            if(dor_zp|dor_abs2)begin
                dor_mem_access_firset<='d0; PC<=cpu_addr+16'd1;
            end
        end

        cpu_addr <= cpu_addr + !dor_abs_over;
             if(dor_zp      )begin dor_zp   ='d0; cpu_addr <= dat; end        //0页
        else if(dor_zpx     )begin dor_zpx  ='d0; cpu_addr[7:0] <= cpu_addr[7:0] + ((dor_ldx|dor_stx)?Y:X); end
        else if(dor_abs     )begin dor_abs  ='d0; dor_abs2 ='b1;  {dor_abs_over,tmp_addr[7:0]} <= {1'b0,dat}+{1'b0,(dor_aby|(dor_ldx&dor_abx))?Y:dor_abx?X:8'h00}; end
        else if(dor_abs2    )begin
            dor_abs_over_sta = dor_abs_over;        //需要定义多一个dor_abs_over_sta来处理dor_abs_over的多冲突驱动
            dor_abx<='d0; dor_aby<='d0;
            dor_abs2='d0; cpu_addr[15:0]<={dat,tmp_addr[7:0]};
            //需要针对回写指令增加额外的一个周期
            if(dor_abx|dor_aby)begin        /*如果是直接abs.则不需要增加额外的周期*/
                if((dor_sta|dor_writeback)&~dor_abs_over)begin
                    //如果没有间接计算没有溢出.则额外插入一个nop
                    dor_nop <= 'b1;
                end
            end
        end
        else if(dor_abs_over)begin dor_abs_over<='d0; dor_abs_over_sta = 0; cpu_addr[15:8]<=cpu_addr[15:8] + 8'd1; end

        //写入指令
        if(~(dor_zp|dor_zpx|dor_abs|dor_abs2|dor_abs_over_sta))begin
            if(dor_sta)begin
                cpu_out_dat <= dor_stx?X:dor_sty?Y:A;
                rw_reg <= 'b0;
                dor_sta <= 'd0;
            end
            dor_restorePC <= 'b1;
        end
        cpu_status <= 'd0;
    end endtask
    reg test;

`define USE_STATUS
`ifdef USE_STATUS
    reg [3:0] cpu_status = 'd0;
`endif
    reg[2:0] opcode = 'd0;

    ////////////////////////////////
    //需要定义一个中断寄存器
    reg dor_nmi = 'b0;
    reg dor_irq = 'd0;
    reg dor_rst = 'd0;

    wire do_nmi =   ~nmi&~dor_nmi;      // 低电平且状态为nmi
    wire do_irq =   ~irq&~dor_irq;
    wire do_rst =   ~dor_rst; //

    ///////////////////////////////

    always @(negedge clk_in) begin
        if(~rw_reg)begin
            rw_reg  <= 'b1;
        end
        insn_reg <= 'd0;
        /////////////////////////////////////////////////////////
        //中断处理
        // if(~rst_n)begin
        //     //`CPU_JMP_ABS('hfffc);
        //     do_fetch_opcode <= 'b1;
        // end
        // else if(~nmi&~dor_nmi)begin
        //     //不可屏蔽中断
        //     //`CPU_JMP_ABS('hfffa);
        //     do_fetch_opcode <= 'b1;
        // end
        // else if(
        //     //(~irq&`DFLG)|dor_irq
        //     (~irq&~dor_irq) &`DFLG
        // )begin
        //     dor_irq <= irq;     //开启中断
        //     //`CPU_JMP_ABS('hfffe);
        //     do_fetch_opcode <= 'b1;
        // end
        if(~rst_n)begin
            //重启
            dor_rst <= rst_n;
            dor_nmi <= ~nmi;        //使他永远不相等
            dor_irq <= ~irq;        //
            //`CPU_JMP_ABS('hfffc);
            do_fetch_opcode <= 'b1;
        end
        else
        ////////////////////////////////////////////////////////
        begin
            /*jsr时序
                |jmp | PCL      | sp | sp+1 | sp+2 | PCH        |
                     |dor_jsr   |pPCH|pPCL  |pPCP* |dor_jmp_abs2|

            有关jsr,brk,rts,rti,jmp的时序逻辑比较复杂,其他的都很简单
            如果参考cpu_status  则会比较直观.但逻辑数量多使用100+个lut. (634->754)
                不过如果使用yosys.使用资源可能会让cpu_status使用的资源比不使用cpu_status的更少?

             */
`ifdef     USE_STATUS
             cpu_status <= cpu_status + 4'd1;
`endif
            if(dor_nop         )begin dor_nop     <='d0; dor_nop<='d0;end //'ea
            else if(do_dma)     begin task_dma_copy; end
            else if(dor_nop1        )begin dor_nop1    <='d0; dor_nop1<='d0; cpu_addr<=cpu_addr+16'd1; end
`ifndef     USE_STATUS
            else if(dor_brk&~dor_pushP&rw_reg)begin dor_pushP  <='b1; dor_pushPCL <='b1; cpu_addr<={8'h01,S}; `CPU_PUSH(cpu_addr[15:8]);tmp_addr<=cpu_addr-16'd1; end
            else if(dor_jsr&dor_pushPCL)begin  dor_jsr<='b0; `CPU_PUSH(tmp_addr[15:8];)  end  //jsr2
            else if(dor_jsr         )begin dor_pushPCL<='b1;dor_jsr2<='b1; cpu_addr <= {8'h01,S}; S<=dat; tmp_addr<=cpu_addr + 16'd1; end             //jsr1
            else if(dor_pushPCL     )begin dor_pushPCL<='b0; `CPU_PUSH(tmp_addr[7:0]);`CPU_ADDR_DEC;end                 //jsr3
            else if(dor_jsr2&~rw_reg)begin dor_jmp_td<='b1; dor_jsr2<='b0; S<=cpu_addr[7:0]-8'd1; cpu_addr<=tmp_addr; tmp_addr[7:0] <= S; end
            else if(dor_jmp_td      )begin dor_jmp_td<='b0; cpu_addr<={dat,tmp_addr[7:0]}; end
            else if(dor_pushP   )begin dor_pushP <='b0; `CPU_PUSH(P);`CPU_ADDR_DEC                              end
            else if(dor_brk     )begin dor_brk   <='d0; `CPU_JMP_ABS('hfffe); S<=cpu_addr[7:0] - 8'd1;                 end

            else if(dor_rti2    )begin dor_rti2<='d0; P<=dat; `CPU_ADDR_INC; end
            else if(dor_jmp     )begin dor_jmp   <='d0; dor_jmp2<='b1; tmp_addr[7:0]<=dat; `CPU_ADDR_INC;  end
            else if(dor_jmp2    )begin dor_jmp2  <='d0; tmp_addr[15:8]<=dat;               `CPU_ADDR_INC;  if(~dor_rts)begin cpu_addr<={dat,tmp_addr[7:0]};end end
            else if(dor_rts     )begin dor_rts   <='d0; S<=cpu_addr[7:0]-8'd1;  cpu_addr<=tmp_addr; dor_nop1<=~dor_rti; dor_rti<='b0; end /*rts先执行jmp1,jmp2*/
            else if(dor_rti     )begin dor_rti2<='b1; dor_rts <='b1; dor_jmp<='b1; dor_jmp2<='b1; tmp_addr<=cpu_addr; cpu_addr<={8'h01,S+8'd1}; end
`else
            else if(dor_jsr)begin
                case (cpu_status)
                    0:begin S<=dat; tmp_addr<=cpu_addr + 16'd1; cpu_addr<={8'h01,S}; end                 //读取低位
                    1:begin `CPU_PUSH(tmp_addr[15:8]); end
                    2:begin `CPU_ADDR_DEC; `CPU_PUSH(tmp_addr[7:0]);  end
                    3:begin S<=cpu_addr[7:0] - 8'd1; cpu_addr<=tmp_addr; tmp_addr[7:0] <=S; end
                    4:begin dor_jsr<='b0; cpu_addr<={dat,tmp_addr[7:0]}; end
                    default:;
                endcase
            end
            else if(dor_brk)begin
                case (cpu_status)
                    0:begin
                        cpu_addr <= {8'h01,S};
                        if(dor_nmi)
                            tmp_addr<=cpu_addr-16'd1;
                        else
                            tmp_addr<=cpu_addr+16'd1;

                        `CPU_PUSH(cpu_addr[15:8]);
                    end
                    1:begin `CPU_ADDR_DEC; `CPU_PUSH(tmp_addr[7:0]);  end
                    2:begin `CPU_ADDR_DEC; `CPU_PUSH(P);              end
                    3:begin
                        dor_jmp<='b1; dor_brk<='b0; cpu_status<='d0;
                        S<=cpu_addr[7:0]-8'd1;
                        if(~dor_rst)begin
                            cpu_addr<=16'hfffc;
                            dor_rst <= rst_n;     //设置寄存器
                        end
                        else if(dor_nmi)begin
                            cpu_addr <=16'hfffa;
                            dor_nmi <= ~nmi;
                        end
                        else begin
                            dor_irq <= ~irq;
                            cpu_addr<=16'hfffe;
                        end
                    end
                    default:;
                endcase
            end
            else if(dor_jmp|(dor_jmp_ind&~dor_zp))begin
                //dor_abs <= 'd0;
                case (cpu_status)
                    0:begin tmp_addr[7:0] <= dat; `CPU_ADDR_INC end
                    1:begin cpu_addr <={dat,tmp_addr[7:0]}; dor_jmp<='d0; dor_jmp_ind<='d0; end
                    default:;
                endcase
                dor_restorePC <= 'b0;
            end
            else if(dor_rti)begin
                case (cpu_status)
                    0:begin cpu_addr<={8'h01,S+8'd1}; end
                    1:begin P <=dat; `CPU_ADDR_INC; end
                    2:begin tmp_addr[7:0]  <=dat; `CPU_ADDR_INC; end
                    3:begin tmp_addr[15:8] <=dat; `CPU_ADDR_INC; end
                    4:begin S <= cpu_addr[7:0]-8'd1; cpu_addr <= tmp_addr; dor_rti<='b0;  end
                    default:;
                endcase
            end
            else if(dor_rts)begin
                case (cpu_status)
                    0:begin cpu_addr<={8'h01,S+8'd1}; end
                    1:begin tmp_addr[7:0]  <=dat; `CPU_ADDR_INC; end
                    2:begin tmp_addr[15:8] <=dat; `CPU_ADDR_INC; end
                    3:begin S <= cpu_addr[7:0]-8'd1; cpu_addr<=tmp_addr; end
                    4:begin `CPU_ADDR_INC; dor_rts<='b0; end
                    default:;
                endcase
            end
`endif
            //有关jmprel,  如果dat是负数,且PCL+dat 大于'h100时,则往前跳,且不跨页. 如果小于'h100,则表示跨页
            else if(dor_jmprel)begin dor_jmprel<='d0; {dor_jmprel_over,cpu_addr[7:0]} <= {1'b0,cpu_addr[7:0]} + {dat[7],dat} + 9'd1; tmp_addr[7:0] <=dat;  end
            else if(dor_jmprel_over)begin
                dor_jmprel_over<='d0;
                if(tmp_addr[7])
                      cpu_addr[15:8] <= cpu_addr[15:8]-8'd1;
                 else cpu_addr[15:8] <= cpu_addr[15:8]+8'd1;
            end
            else if(dor_php)begin dor_php<='d0; dor_push_end<='b1; `CPU_PUSH(P);cpu_addr<={8'h01,S};tmp_addr<=cpu_addr; end
            else if(dor_pha)begin dor_pha<='d0; dor_push_end<='b1; `CPU_PUSH(A);cpu_addr<={8'h01,S};tmp_addr<=cpu_addr; end
            else if(dor_push_end)begin dor_push_end<='d0; S<=cpu_addr[7:0]-8'd1; cpu_addr<=tmp_addr; end
            else if(dor_pla)begin PC<=cpu_addr; dor_pla<='d0; S=S+8'd1; cpu_addr <= {8'h01,S};dor_m2a<='b1;                                end
            else if(dor_plp)begin PC<=cpu_addr; dor_plp<='d0; S=S+8'd1; cpu_addr <= {8'h01,S};dor_m2p<='b1;  end
            else if(dor_m2p)begin dor_m2p<='d0; P <= dat; S <= cpu_addr[7:0];       `CPU_ADDR_INC;dor_restorePC<='b1;  end
            else if(dor_m2a)begin dor_m2a<='d0; A <= dat; S <= cpu_addr[7:0]; `FLG_UPDATE_NZ(dat); `CPU_ADDR_INC;dor_restorePC<='b1;  end
            //rti 相当于执行 plp | jmp $sp
            else if(dor_addr_sp)begin S<=cpu_addr[7:0]; end         //复制到sp寄存器中
            else if(dor_iny)begin dor_iny<='d0; Y = Y + 8'd1; `FLG_UPDATE_NZ(Y);/*.c8*/     end
            else if(dor_dey)begin dor_dey<='d0; Y = Y - 8'd1; `FLG_UPDATE_NZ(Y);/*.88*/     end
            else if(dor_inx)begin dor_inx<='d0; X = X + 8'd1; `FLG_UPDATE_NZ(X);/*.e8*/     end
            else if(dor_dex)begin dor_dex<='d0; X = X - 8'd1; `FLG_UPDATE_NZ(X);/*.ca*/     end
            else if(dor_txa)begin dor_txa<='d0; A<=X;       `FLG_UPDATE_NZ(A);  /*.8a*/     end
            else if(dor_tay)begin dor_tay<='d0; Y<=A;       `FLG_UPDATE_NZ(Y);  /*.a8*/     end
            else if(dor_tax)begin dor_tax<='d0; X<=A;       `FLG_UPDATE_NZ(X);  /*.aa*/     end
            else if(dor_tya)begin dor_tya<='d0; A<=Y;       `FLG_UPDATE_NZ(A);  /*.98*/     end
            else if(dor_txs)begin dor_txs<='d0; S<=X;       `FLG_UPDATE_NZ(S);  /*.9a*/     end
            else if(dor_tsx)begin dor_tsx<='d0; X<=S;       `FLG_UPDATE_NZ(X);  /*.ba*/     end
            else if(dor_clc)begin dor_clc<='d0;             `CFLG<='b0;         /*.18*/     end
            else if(dor_cli)begin dor_cli<='d0;             `IFLG<='b0;         /*.38*/     end
            else if(dor_clv)begin dor_clv<='d0;             `VFLG<='b0;         /*.b8*/     end
            else if(dor_cld)begin dor_cld<='d0;             `DFLG<='b0;         /*.d8*/     end
            else if(dor_sec)begin dor_sec<='d0;             `CFLG<='b1;         /*.38*/     end
            else if(dor_sei)begin dor_sei<='d0;             `IFLG<='b1;         /*.78*/     end
            else if(dor_sed)begin dor_sed<='d0;             `DFLG<='b1;         /*.f8*/     end
            else if(dor_mem_access)begin task_mem_access;                                   end
            else if(dor_bit)begin dor_bit <= 'd0;`NFLG <= dat[7];`VFLG <= dat[6]; `ZFLG <=(dat&A)=='d0; end
            else if(dor_lda)begin dor_lda<='b0;dor_ldx<='b0;dor_ldy<='b0; if(dor_ldx) X <= dat; else if(dor_ldy) Y<=dat; else A<=dat; `FLG_UPDATE_NZ(dat);cpu_addr<=cpu_addr+16'd1; if(dor_restorePC)begin cpu_addr<=PC; end dor_restorePC<='b0;  end
            else if(dor_inc)begin dor_inc<='b0; cpu_out_dat=dat+8'd1;`FLG_UPDATE_NZ(cpu_out_dat); end
            else if(dor_dec)begin dor_dec<='b0; cpu_out_dat=dat-8'd1;`FLG_UPDATE_NZ(cpu_out_dat); end

            else if(dor_asl)begin dor_asl<='b0; cpu_out_dat={(dor_shift_A?A[6:0]:dat[6:0]),1'b0 };`CFLG <= dor_shift_A?A[7]:dat[7]; `FLG_UPDATE_NZ(cpu_out_dat);if(dor_shift_A)begin A<=cpu_out_dat; dor_shift_A<='b0; end  end
            else if(dor_lsr)begin dor_lsr<='b0; cpu_out_dat={ 1'b0,(dor_shift_A?A[7:1]:dat[7:1])};`CFLG <= dor_shift_A?A[0]:dat[0]; `FLG_UPDATE_NZ(cpu_out_dat);if(dor_shift_A)begin A<=cpu_out_dat; dor_shift_A<='b0; end  end
            else if(dor_rol)begin dor_rol<='b0; cpu_out_dat={(dor_shift_A?A[6:0]:dat[6:0]),`CFLG};`CFLG <= dor_shift_A?A[7]:dat[7]; `FLG_UPDATE_NZ(cpu_out_dat);if(dor_shift_A)begin A<=cpu_out_dat; dor_shift_A<='b0; end  end
            else if(dor_ror)begin dor_ror<='b0; cpu_out_dat={`CFLG,(dor_shift_A?A[7:1]:dat[7:1])};`CFLG <= dor_shift_A?A[0]:dat[0]; `FLG_UPDATE_NZ(cpu_out_dat);if(dor_shift_A)begin A<=cpu_out_dat; dor_shift_A<='b0; end  end

            else if(dor_writeback)begin dor_writeback<='b0; /*dec,inc,计算后回写需要额外的一个周期*/rw_reg<='b0; end
            else if(dor_alu)begin
                dor_alu<='d0;
                dor_cpx<='d0;
                dor_cpy<='d0;
                if(opcode!=`OP_CMP)begin
                    A <= result;
                end
                `CFLG <= flg_out[0];
                `ZFLG <= flg_out[1];
                `VFLG <= flg_out[2];
                `NFLG <= flg_out[3];
                cpu_addr <= cpu_addr + 16'd1;
                if(dor_restorePC)begin
                    dor_restorePC <='d0; cpu_addr <= PC;
                end
            end
            else if(dor_restorePC)begin dor_restorePC <='d0; cpu_addr <= PC; end
            else begin
                `ifdef USE_STATUS
                cpu_status <= 'd0;
                `endif
                `CPU_ADDR_INC;
                //解码部分
                //种类
                insn_reg <= insn_dat;

                //一些中断处理
                dor_nmi    <= ~nmi;
                dor_irq    <= ~irq;

                //if(rst_n)begin dor_rst  <= ~rst_n; end        //与其他的不同


                //以下是单指令
                dor_jsr      = insn_dat=='h20;
                dor_jmp      = insn_dat=='h4c;
                dor_jmp_ind  = insn_dat=='h6c;

                dor_brk = insn_dat=='h00;
                dor_rti = insn_dat=='h40;
                dor_rts = insn_dat=='h60;

                dor_php = insn_dat=='h08;
                dor_plp = insn_dat=='h28;
                dor_pha = insn_dat=='h48;
                dor_pla = insn_dat=='h68;

                dor_dey = insn_dat=='h88;
                dor_tay = insn_dat=='ha8;
                dor_iny = insn_dat=='hc8;
                dor_inx = insn_dat=='he8;

                dor_txa = insn_dat=='h8a;
                dor_tax = insn_dat=='haa;
                dor_dex = insn_dat=='hca;
                dor_nop = insn_dat=='hea;

                dor_bpl = insn_dat=='h10;
                dor_bmi = insn_dat=='h30;
                dor_bvc = insn_dat=='h50;
                dor_bvs = insn_dat=='h70;
                dor_bcc = insn_dat=='h90;
                dor_bcs = insn_dat=='hb0;
                dor_bne = insn_dat=='hd0;
                dor_beq = insn_dat=='hf0;

                dor_clc = insn_dat=='h18;
                dor_cli = insn_dat=='h58;
                dor_clv = insn_dat=='hb8;
                dor_cld = insn_dat=='hd8;

                dor_sec = insn_dat=='h38;
                dor_sei = insn_dat=='h78;
                dor_sed = insn_dat=='hf8;

                dor_tya = insn_dat=='h98;
                dor_txs = insn_dat=='h9a;
                dor_tsx = insn_dat=='hba;

                dor_cpx = (insn_dat=='he0)|(insn_dat=='he4)|(insn_dat=='hec);
                dor_cpy = (insn_dat=='hc0)|(insn_dat=='hc4)|(insn_dat=='hcc);

                opcode  <= (dor_cpx)?`OP_CMP:dat[7:5];      //cpy与cmp共用[7:5]

                dor_bit = (insn_dat=='h24)|(insn_dat=='h2c);

                dor_ldx = (insn_dat[7:5]=='d5)&(insn_dat[1:0]=='d2)&~(dor_tsx|dor_tax);
                dor_ldy = (insn_dat[7:5]=='d5)&(insn_dat[1:0]=='d0)&~(dor_tay|dor_clv|(insn_dat[4:0]=='h10));

                dor_stx = (insn_dat[7:5]=='d4)&(insn_dat[1:0]=='d2)&~(dor_txs|dor_txa);
                dor_sty = (insn_dat[7:5]=='d4)&(insn_dat[1:0]=='d0)&~(dor_dey|dor_tya|(insn_dat[4:0]=='h10));

                dor_sta = (insn_dat[7:5]=='h4&&insn_dat[1:0]=='d1)|(dor_stx|dor_sty);
                dor_lda = (insn_dat[7:5]=='h5&&insn_dat[1:0]=='d1)|(dor_ldx|dor_ldy);

                dor_dec = (insn_dat[1:0]=='d2)&(insn_dat[7:5]=='d6)&~dor_dex;
                dor_inc = (insn_dat[1:0]=='d2)&(insn_dat[7:5]=='d7)&~dor_nop;

                dor_asl = (insn_dat[1:0]=='d2)&(insn_dat[7:5]=='d0);
                dor_lsr = (insn_dat[1:0]=='d2)&(insn_dat[7:5]=='d2);
                dor_rol = (insn_dat[1:0]=='d2)&(insn_dat[7:5]=='d1);
                dor_ror = (insn_dat[1:0]=='d2)&(insn_dat[7:5]=='d3);
                dor_shift_A = insn_dat[4:0]=='ha;

                dor_alu <=
                    ((insn_dat[1:0]==3'd1)&~(dor_sta|dor_lda))
                    |dor_cpx|dor_cpy
                ;

                dor_ind_x = (insn_dat[4:2]=='d0) & (insn_dat[0]);
                dor_ind_y = (insn_dat[4:2]=='d4) & (insn_dat[0]);

                dor_zpx   = (insn_dat[4:2]=='d5)|dor_ind_x;
                dor_zp    = (insn_dat[4:2]=='d1)|dor_jmp_ind|dor_ind_x|dor_ind_y|dor_zpx;
                dor_abx   = (insn_dat[4:2]=='d7);
                dor_aby   = ((insn_dat[4:2]=='d6) & (insn_dat[0]))|dor_ind_y;       //0位需要为1
                dor_abs   = dor_abx|dor_aby|dor_ind_x|
                    ((insn_dat[4:2]=='d3) &~(dor_jmp|dor_jmp_ind)); //如果在jmd里置为0.则少了一个lut

                dor_writeback <=
                    dor_inc|dor_dec|
                    ((dor_asl|dor_lsr|dor_rol|dor_ror)&~dor_shift_A);
                dor_mem_access_firset <= 'b1;
                if(insn_dat[4:0]=='h10)begin
                    if(
                     `JMP_BPL
                    |`JMP_BMI
                    |`JMP_BEQ
                    |`JMP_BNE
                    |`JMP_BVC
                    |`JMP_BVS
                    |`JMP_BCC
                    |`JMP_BCS
                    )begin
                        dor_jmprel <= 'b1;
                    end
                    else begin
                        dor_nop1 <= 'b1;
                    end
                end
            end

        end
    end



    /*
详细周期可以查看另一个项目模拟器项目下的 "/doc/有关指令周期与定义.txt"
    abs,zeropage操作步骤为
    1.读取操作码.       初始化地址寄存器为X或Y或0
    2.读取目标地址低.   地址寄存器[8:0]     增加该值
    3.读取目标地址高.   设置地址寄存器[15:8].设置溢出标志. 指向地址线
        3.1             如果溢出则执行,地址线需要加溢出位. 如果是zerepage则不会计算该指令
    4.读取目标数据.并执行

例子如
ORA abx ($1d $23 $81)        :注,程序地址为$0a,  下面显示的是地址线值
    |$0a|$0b|$0c|$1a3|          x=0x80
    |$0a|$0b|$0c|$103|$203|     x=0xe0

    以下是时钟与地址线变化(addr为地址线)
    zp
      fall                      fall delay(20~50ns)
    1.read opcode1.             addr += 1
    2.read opcode2.             addr = opcode2
    3.exec                      addr = PC + 2

    zpx
    1.read opcode1              addr += 1
    2.read opcode2              addr =  opcode2
    3.addr add                  addr[7:0] += X
    4.exec                      addr = PC + 2

    abs
    1.read opcode1              addr += 1
    2.read opcode2              addr += 1;
    3.read opcode3              addr = opcode2 + opcode3*0x100
    4.exec                      addr = PC + 3.

    abx,aby
    1.read opcode1                          addr += 1
    2.read opcode2                          addr += 1;
    3.read opcode3                          addr = ((opcode2 + X or Y) & 'hff) + opcode3*0x100;
    3(1).if((opcode2 + X or Y)>=0x100)      addr += 0x100
    4.exec                      addr = PC + 3.

    izx
    1.read opcode1              addr += 1
    2.read opcode2              addr =  opcode2
    3.addr add                  addr[7:0] += x
    4.read adr1                 addr += 1
    5.read adr2                 addr = adr1 + adr2*0x100
    6.exec                      addr = PC + 3;

    izy
    1.read opcode1              addr += 1
    2.read opcode2              addr =  opcode2
    3.read adr1                 addr += 1
    4.read adr2                 addr = (adr1 + Y)[7:0] adr2*0x100
    4(1).if(adr1+Y)>0xFF        addr += 0x100
    5.exec                      addr = PC + 3;

    jmp rel
    1.read opcode1              addr += 1
    2.read opcode2              addr += 1
    2(1).cond T                 {o,addr[7:0]} = {'b0,addr[7:0]} + opcode2
    2(2).if(o)                  addr += 0x100

        (注1),编号(1)是可能需要增加一个周期
        (注2).rel 如果条件为真.则加一个周期.如果是跨页.则需要再加一个周期

BRK     |PUSH PC|PUSH P|JMP $fffe|
JSR     |PUSH PC|*jmp $PC+2|


PUSH PC:->|do push PCH | do push PCL|
PUSH P :->|do push P|
JMP $xxxx:|tmp_addr[7:0] = dat| jmp {dat,tmp_addr}
    *如果是绝对地址.则tmp_addr则是在提前处理




//有关一些时序出入
    JSR 指令原本是
        |$C0|$C1|$1FF|$1FF|$1FE|$C2|12FD|
        |adr|adr|<-----SP----->|adr|jmp |
        |  0|  1|   2|   3|   4|  5|   6|
    变为
        |$C0|$C1|$1FF|$1FE|$1FE|$C2|12FD|

    lda与sta的 abs时序问题
        lda 针对abx,aby 跨页访问时.会增加一个周期
        sta 则无条件增加一个周期

    rts 时序问题.(本源码少了一个时钟)
        |rts|tmp|               |下一个地址
        |01 |02 |sp1|sp2|sp3|tmp|next


各指令的时序

    brk     |$0a    |$0b    |$1fa   |$1f9   |$1f8   |$7ffe  |$7fff  |_irq_|     7cycle
    jsr     |$0a    |$0b    |$1fa   |$1fa   |$1f9   |$0c    |jmp    |   6cycle
    rts     |$0a    |$0b    |$1fb   |$1fc   |$1fd   |jmp-1  |jmp    |   6cycle
    rti     |$0a    |$0b    |$1fb   |$1fc   |$1fd   |$1fe   |$2cd   |   6cycle
    jmp     |$0a    |$0b    |$0c    |jmp            //3cycle
    jmp     |$0a    |$0b    |adr+0  |adr+1  |jmp    //4cycle
    clc     |$0a    |$0b    |$0b(next)              //2cycle
    cli,clv,cld,sec,sei,sed 同上


    */

endmodule
